package com.winsdom.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.winsdom.domain.dto.FinishedThreeTableDTO;
import com.winsdom.domain.vo.BuildingResourceVO;
import com.winsdom.entity.ReadingRecord;
import com.winsdom.entity.ReadingTask;
import com.winsdom.entity.TaskExecutionLog;
import com.winsdom.entity.ThreeTables;
import com.winsdom.exception.BusinessException;
import com.winsdom.mapper.CategoryMapper;
import com.winsdom.mapper.ReadingRecordMapper;
import com.winsdom.mapper.TaskExecutionLogMapper;
import com.winsdom.mapper.ThreeTablesMapper;
import com.winsdom.service.IReadingRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.winsdom.service.IReadingTaskService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.PostConstruct;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * <p>
 * 抄表记录表 服务实现类
 * </p>
 *
 * @author 
 * @since 2025-05-12
 */
@Service
@Slf4j
public class ReadingRecordServiceImpl extends ServiceImpl<ReadingRecordMapper, ReadingRecord> implements IReadingRecordService {
    @Autowired
    private ReadingRecordMapper readingRecordMapper;
    @Autowired
    private IReadingTaskService iReadingTaskService;
    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private ThreeTablesMapper threeTablesMapper;
    @Autowired
    private TaskExecutionLogMapper taskExecutionLogMapper;
    @Value("${scheduled.meter.time}")
    private String meterTime;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateFinished(FinishedThreeTableDTO finishedThreeTableDTO) {
        //获取修改前 已抄表 的 读表时间
        LambdaQueryWrapper<ReadingRecord> recordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        recordLambdaQueryWrapper.eq(ReadingRecord::getId,finishedThreeTableDTO.getId());
        ReadingRecord readingRecord = readingRecordMapper.selectOne(recordLambdaQueryWrapper);
        LocalDateTime readTime = readingRecord.getReadTime();
        Integer currentReading = readingRecord.getCurrentReading();

        if(finishedThreeTableDTO.getId()==null || finishedThreeTableDTO.getId()<0 ){
            throw new BusinessException("没找到被抄表信息！", HttpStatus.BAD_REQUEST);
        }

        if(finishedThreeTableDTO.getCurrentReading()<readingRecord.getLastReading() || finishedThreeTableDTO.getCurrentReading()==null){
            throw new BusinessException("抄表数据错误！", HttpStatus.BAD_REQUEST);
        }
        if(finishedThreeTableDTO.getReadTime().isBefore(readingRecord.getLastReadTime()) ||finishedThreeTableDTO.getReadTime()==null){
            throw new BusinessException("抄表时间错误！", HttpStatus.BAD_REQUEST);
        }

        if(finishedThreeTableDTO.getReadTime().getMonthValue()!=readTime.getMonthValue() || finishedThreeTableDTO.getReadTime().getYear()!=readTime.getYear()){
            throw new BusinessException("抄表时间应在本月！", HttpStatus.BAD_REQUEST);
        }

        //获取 已抄表 的下月的表的id
        LambdaQueryWrapper<ReadingRecord> recordLambdaQueryWrapper2 = new LambdaQueryWrapper<>();
        recordLambdaQueryWrapper2.eq(ReadingRecord::getLastReadTime,readTime).eq(ReadingRecord::getLastReading,currentReading);
//                .isNull(ReadingRecord::getCurrentReading);
        ReadingRecord readingRecord2 = readingRecordMapper.selectOne(recordLambdaQueryWrapper2);

        //修改 已抄表的抄表信息
        LambdaUpdateWrapper<ReadingRecord> recordLambdaUpdateWrapper = new LambdaUpdateWrapper<>();

        recordLambdaUpdateWrapper.eq(ReadingRecord::getId, finishedThreeTableDTO.getId())
                .eq(ReadingRecord::getStatus,0);
        recordLambdaUpdateWrapper.set(ReadingRecord::getReadTime, finishedThreeTableDTO.getReadTime())
                .set(ReadingRecord::getCurrentReading, finishedThreeTableDTO.getCurrentReading());
        readingRecordMapper.update(null, recordLambdaUpdateWrapper);

        //修改 已抄表的下月的抄表信息
        if(readingRecord2!=null){
            LambdaUpdateWrapper<ReadingRecord> recordLambdaUpdateWrapper2 = new LambdaUpdateWrapper<>();

            recordLambdaUpdateWrapper2.eq(ReadingRecord::getId, readingRecord2.getId())
                    .eq(ReadingRecord::getStatus,0);
            recordLambdaUpdateWrapper2.set(ReadingRecord::getLastReadTime, finishedThreeTableDTO.getReadTime())
                    .set(ReadingRecord::getLastReading,finishedThreeTableDTO.getCurrentReading());
            readingRecordMapper.update(null, recordLambdaUpdateWrapper2);
        }

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateUnFinishedBatch(List<FinishedThreeTableDTO> finishedThreeTableDTOs) {
        if(!finishedThreeTableDTOs.isEmpty()) {
            Integer taskId=0;
            for (FinishedThreeTableDTO dto : finishedThreeTableDTOs) {
                //获取修改前 已抄表 的 读表时间
                LambdaQueryWrapper<ReadingRecord> recordLambdaQueryWrapper = new LambdaQueryWrapper<>();
                recordLambdaQueryWrapper.eq(ReadingRecord::getId, dto.getId());
                ReadingRecord readingRecord = readingRecordMapper.selectOne(recordLambdaQueryWrapper);
                taskId=readingRecord.getTaskId();
                //检查抄表任务是否完成
                QueryWrapper<ReadingTask> readingTaskQueryWrapper = new QueryWrapper<>();
                readingTaskQueryWrapper.eq("id",taskId);
                ReadingTask task = iReadingTaskService.getOne(readingTaskQueryWrapper);
                if(Objects.equals(task.getNeedTotal(), task.getFinishedTotal()))
                    throw new BusinessException("该任务已完成抄表！", HttpStatus.BAD_REQUEST);

                LocalDateTime lastReadTime = readingRecord.getLastReadTime();
                if (dto.getId() == null || dto.getId() < 0) {
                    throw new BusinessException("没找到被抄表信息！", HttpStatus.BAD_REQUEST);
                }
                if (dto.getCurrentReading() < readingRecord.getLastReading() || dto.getCurrentReading() == null) {
                    throw new BusinessException("抄表数据错误", HttpStatus.BAD_REQUEST);
                }
                if (dto.getReadTime().isBefore(lastReadTime) || dto.getReadTime() == null) {
                    throw new BusinessException("抄表时间错误", HttpStatus.BAD_REQUEST);
                }
                lastReadTime = lastReadTime.plusMonths(1);
                log.info("lastReadTime:{}",lastReadTime);
                log.info("dto:{}",dto);
                if (dto.getReadTime().getMonthValue() != lastReadTime.getMonthValue() && dto.getReadTime().getYear() != lastReadTime.getYear()) {
                    throw new BusinessException("抄表时间应在本月！", HttpStatus.BAD_REQUEST);
                }

                LambdaUpdateWrapper<ReadingRecord> recordLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
                recordLambdaUpdateWrapper.eq(ReadingRecord::getId, dto.getId())
                        .eq(ReadingRecord::getStatus, 0);
                recordLambdaUpdateWrapper.set(ReadingRecord::getReadTime, dto.getReadTime())
                        .set(ReadingRecord::getCurrentReading, dto.getCurrentReading());
                readingRecordMapper.update(null, recordLambdaUpdateWrapper);

            }
            //修改抄表记录表的已完成任务
            int size = finishedThreeTableDTOs.size();
            QueryWrapper<ReadingTask> readingTaskQueryWrapper = new QueryWrapper<>();
            readingTaskQueryWrapper.eq("id",taskId);
            ReadingTask task = iReadingTaskService.getOne(readingTaskQueryWrapper);
            LambdaUpdateWrapper<ReadingTask> lambdaUpdateWrapper=new LambdaUpdateWrapper<>();
            Integer finishedTotal = task.getFinishedTotal();
            finishedTotal+=size;
            lambdaUpdateWrapper.set(ReadingTask::getFinishedTotal,finishedTotal);
            if(finishedTotal.equals(task.getNeedTotal()))
                lambdaUpdateWrapper.set(ReadingTask::getCompleteTime,LocalDateTime.now()).set(ReadingTask::getStatus,1);
            lambdaUpdateWrapper.eq(ReadingTask::getId,taskId);
            if(finishedTotal>task.getNeedTotal())
                throw new BusinessException("抄表数量异常",HttpStatus.BAD_REQUEST);
            iReadingTaskService.update(lambdaUpdateWrapper);
        }else {
            throw new BusinessException("未收到抄表信息",HttpStatus.BAD_REQUEST);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void meterTask() {
        try {
            // 动态获取当前时间，并设置任务时间为当月一号 09:00:00
            LocalDateTime now = LocalDateTime.now();
            LocalDateTime taskTime = now.withDayOfMonth(1).withHour(9).withMinute(0).withSecond(0);
            meter(taskTime);
        }catch (Exception e){
            log.error("事务执行失败，回滚中...", e);
            throw new BusinessException("事务执行失败", HttpStatus.BAD_REQUEST);
        }

    }

    private void meter(LocalDateTime taskTime) {
        LocalDateTime taskTimeJian1 = taskTime.minusMonths(1);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String taskTimeStr = taskTime.format(formatter);
        log.info("当前任务时间: {}", taskTimeStr);
        //获取所有楼盘Id
        List<Long> allBuildings = categoryMapper.getAllBuildings();
        if(allBuildings!=null){
            for (Long buildingId : allBuildings){
                //生成抄表初始任务（未计算抄没抄表）
                ReadingTask readingTask = new ReadingTask();
                readingTask.setGenerateDate(LocalDate.from(taskTime));
                readingTask.setNeedTotal(0);
                readingTask.setFinishedTotal(0);
                readingTask.setReadingCycle("每月一次");
                readingTask.setCategoryId(buildingId.intValue());
                readingTask.setStatus(0);
                iReadingTaskService.save(readingTask);
                //得到任务ID
                Integer readingTaskId = readingTask.getId();
                log.info("任务ID:{}",readingTaskId);
                //根据楼盘id查询资源
                List<BuildingResourceVO> buildingResource = categoryMapper.getBuildingResource(buildingId);
                List<Long> resourceIds = buildingResource.stream()
                        .map(BuildingResourceVO::getId)
                        .collect(Collectors.toList());
                log.info("楼盘下的资源集合id：{}",resourceIds);
                if(resourceIds.isEmpty()) {
                    QueryWrapper<ReadingTask> readingTaskQueryWrapper = new QueryWrapper<>();
                    readingTaskQueryWrapper.eq("id",readingTaskId);
                    iReadingTaskService.remove(readingTaskQueryWrapper);
                    continue;
                } else {
                    for (Long resourceId:resourceIds){
                        //根据资源id查询三表,添加抄表记录
                        LambdaQueryWrapper<ThreeTables> threeTablesLambdaQueryWrapper=new LambdaQueryWrapper<>();
                        threeTablesLambdaQueryWrapper.eq(ThreeTables::getCategoryId,resourceId);
                        List<ThreeTables> threeTable = threeTablesMapper.selectList(threeTablesLambdaQueryWrapper);
                        log.info("资源对应的表：{}", threeTable);
                        if(!threeTable.isEmpty()) {
                            for (ThreeTables tables : threeTable) {
                                LambdaQueryWrapper<ReadingRecord> recordLambdaQueryWrapper = new LambdaQueryWrapper<>();
                                recordLambdaQueryWrapper.eq(ReadingRecord::getTableId, tables.getId());
                                Integer selectCount = readingRecordMapper.selectCount(recordLambdaQueryWrapper);
                                //如果该表还没有过抄表记录，根据表的初始读数生成抄表记录
                                if (selectCount < 1) {
                                    ReadingRecord readingRecord = new ReadingRecord();
                                    readingRecord.setTaskId(readingTaskId);
                                    readingRecord.setTableId(tables.getId());
                                    readingRecord.setLastReadTime(LocalDateTime.from(taskTime));
                                    readingRecord.setLastReading(tables.getSwot());
                                    readingRecord.setReadTime(taskTime);
                                    readingRecord.setCurrentReading(null);
                                    readingRecord.setStatus(0);
                                    readingRecordMapper.insert(readingRecord);
                                } else {
                                    int year = taskTimeJian1.getYear();
                                    String s = taskTimeJian1.getMonthValue() > 10 ? String.valueOf(taskTimeJian1.getMonthValue()) : ("0" + taskTimeJian1.getMonthValue());
                                    String date = year + "-" + s;
                                    ReadingRecord lastReadingRecord = readingRecordMapper.getReadingRecordByIdAndLastTime(tables.getId(), date);
                                    ReadingRecord readingRecord = new ReadingRecord();
                                    readingRecord.setTaskId(readingTaskId);
                                    readingRecord.setTableId(tables.getId());
                                    readingRecord.setLastReadTime(lastReadingRecord.getReadTime());
                                    readingRecord.setLastReading(lastReadingRecord.getCurrentReading());
                                    readingRecord.setReadTime(taskTime);
                                    readingRecord.setCurrentReading(null);
                                    readingRecord.setStatus(0);
                                    log.info("readingRecord:{}",readingRecord);
                                    readingRecordMapper.insert(readingRecord);
                                }
                            }
                        }
                    }
                }
                //查找生成的抄表数量
                LambdaQueryWrapper<ReadingRecord> recordLambdaQueryWrapper=new LambdaQueryWrapper<>();
                recordLambdaQueryWrapper.eq(ReadingRecord::getTaskId,readingTaskId);
                Integer meterCount = readingRecordMapper.selectCount(recordLambdaQueryWrapper);
                //修改任务表
                LambdaUpdateWrapper<ReadingTask> lambdaUpdateWrapper=new LambdaUpdateWrapper<>();
                lambdaUpdateWrapper.set(ReadingTask::getNeedTotal,meterCount).eq(ReadingTask::getId,readingTaskId);
                iReadingTaskService.update(lambdaUpdateWrapper);
            }
        }
    }

    @Scheduled(cron = "${scheduled.meter.time}")
    public void DingShiMeterTask() {
        String[] s = meterTime.split(" ");
        int SECOND=Integer.parseInt(s[0]);
        int MINUTE=Integer.parseInt(s[1]);
        int HOUR=Integer.parseInt(s[2]);
        int DAY=Integer.parseInt(s[3]);
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime startTime = LocalDateTime.of(2025, 5, DAY, HOUR, MINUTE, SECOND);
        if (now.isBefore(startTime)) {
            log.info("当前时间早于2025-05-01 09:00:00，定时任务尚未开始执行。");
            return;
        }
        if (isTaskExecuted(now)) {
            log.info("任务已执行过，跳过本次执行。");
            return;
        }
        try {
            meterTask();
            saveTaskExecutionLog(now, "SUCCESS", "任务执行成功");
        } catch (Exception e) {
            log.error("任务执行失败：{}", e.getMessage());
            saveTaskExecutionLog(now, "FAILED", "任务执行失败：" + e.getMessage());
        }
    }
    @Transactional(rollbackFor = Exception.class)
    @PostConstruct
    public void init() {
        String[] s = meterTime.split(" ");
        int SECOND=Integer.parseInt(s[0]);
        int MINUTE=Integer.parseInt(s[1]);
        int HOUR=Integer.parseInt(s[2]);
        int DAY=Integer.parseInt(s[3]);
        LocalDateTime now = LocalDateTime.now();
        int currentYear = now.getYear();
        int currentMonth = now.getMonthValue();
        for (int year = 2025; year <= currentYear; year++) {
            int startMonth = (year == 2025) ? 5 : 1;
            int endMonth = (year == currentYear) ? currentMonth : 12;
            for (int month = startMonth; month <= endMonth; month++) {
                LocalDateTime executionTime = LocalDateTime.of(year, month, DAY, HOUR, MINUTE, SECOND);
                if (isTaskExecuted(executionTime)) {
                    log.info("任务已在{}年{}月1日执行过，跳过本次检查。", year, month);
                    continue;
                }
                if (executionTime.isBefore(now)) {
                    log.info("发现未执行的任务，正在补跑{}年{}月1日的任务。", year, month);
                    try {
                        meterTask(executionTime);
                        saveTaskExecutionLog(executionTime, "SUCCESS", "任务补跑成功");
                    } catch (Exception e) {
                        log.error("任务补跑失败：{}", e.getMessage());
                        saveTaskExecutionLog(executionTime, "FAILED", "任务补跑失败：" + e.getMessage());
                    }
                }
            }
        }
    }

    private boolean isTaskExecuted(LocalDateTime executionTime) {
        String taskName = "DingShiMeterTask";
        int count = taskExecutionLogMapper.existsByTaskNameAndExecutionTime(taskName, executionTime);
        return count > 0;
    }

    private void saveTaskExecutionLog(LocalDateTime executionTime, String status, String message) {
        TaskExecutionLog taskExecutionLog = new TaskExecutionLog();
        taskExecutionLog.setTaskName("DingShiMeterTask");
        taskExecutionLog.setExecutionTime(executionTime);
        taskExecutionLog.setStatus(status);
        taskExecutionLog.setMessage(message);
        taskExecutionLogMapper.insert(taskExecutionLog);
    }

    @Transactional(rollbackFor = Exception.class)
    void meterTask(LocalDateTime taskTime) {
        try {
            meter(taskTime);
        }catch (Exception e){
            log.error("事务执行失败，回滚中...", e);
            throw new BusinessException("事务执行失败", HttpStatus.BAD_REQUEST);
        }
    }

}